# To change this template, choose Tools | Templates
# and open the template in the editor.
require 'utility/utility'
require 'interfaces/data_store'
require 'benchmarking/bench'
require 'similarity/cosine_sim'
require 'similarity/jaccard'
require 'similarity/pearson'

# Versione attuale
class Interfaces
  attr_accessor :utenti,:data,:data_1,:data_2,:data_3,:data_store,:data_store_1,:data_store_2,:data_store_3,:centroide,:type,:method,:fullmatrix
  def initialize(users,centroide)
    @centroide= centroide
    @utenti= users
    @data= self.build_matrix(0)
    @data_1= self.build_matrix(1)
    @data_2= self.build_matrix(2)
    @data_3= self.build_matrix(3)
    @fullmatrix= self.buildfullmatrix()
  end
  # Costruisce una matrice con tutti i contesti tranne lo 0
  def buildfullmatrix
    matrix= []

    self.utenti.each{|u|
      v= []
      v= v.concat(u.context_1)
      v= v.concat(u.context_2)
      v= v.concat(u.context_3)

      matrix.push(v)
    }

    matrix.delete_at((self.centroide-1))
    return matrix
  end
  # Itera all'utetnte successivo
  def next_centroid
    
  end
  # Cambia l'utente con un'utente custom
  def change_centroid
  end
  def build_matrix(contesto=0)   
  
    matrix= Util.users_to_matrix(self.utenti, contesto)
    matrix.delete_at((self.centroide-1))
    return matrix
  end
  # Prepara i dati per i test
  def prepare_data(clustering_type, dimensione)
    case clustering_type
      when  'no'
        self.data_store= DataStore.new(self.data, [0..self.utenti.size-1])

          self.data_store_1= DataStore.new(self.data_1, [0..self.utenti.size-1])
          self.data_store_2= DataStore.new(self.data_2, [0..self.utenti.size-1])
          self.data_store_3= DataStore.new(self.data_3, [0..self.utenti.size-1])
    when 'hierarchical'
      hc= Hierarchical.new(self.build_matrix, dimensione)
      pos= hc.get_cluster((self.centroide-1))
      self.data_store = DataStore.new((hc.dataclust[pos]),(hc.clusters[pos].elementi))
           self.data_store_1= DataStore.new(self.build_cluster_matrix((hc.clusters[pos].elementi), 1),(hc.clusters[pos].elementi))
           self.data_store_2= DataStore.new(self.build_cluster_matrix((hc.clusters[pos].elementi), 2),(hc.clusters[pos].elementi))
          self.data_store_3= DataStore.new(self.build_cluster_matrix((hc.clusters[pos].elementi), 3),(hc.clusters[pos].elementi))
    when 'simple'
      elementi= SimpleCluster.clusterize((self.centroide-1), self.build_matrix, dimensione).elementi
            self.data_store= DataStore.new(SimpleCluster.cluster((self.centroide-1), self.build_matrix, dimensione),
            elementi)
          self.data_store_1= DataStore.new(self.build_cluster_matrix(elementi,1),elementi)
          self.data_store_2= DataStore.new(self.build_cluster_matrix(elementi,2),elementi)
          self.data_store_3= DataStore.new(self.build_cluster_matrix(elementi,3),elementi)
    end
  end
  def build_cluster_matrix(elementi,contesto=0)
    matrix=[]
    case contesto
    when 0
    elementi.each{|i|
      matrix.push(self.data[i])
    }
        when 1
    elementi.each{|i|
      matrix.push(self.data_1[i])
    }
        when 2
    elementi.each{|i|
      matrix.push(self.data_2[i])
    }
        when 3
    elementi.each{|i|
      matrix.push(self.data_3[i])
    }
    end

    return matrix
  end

  def predici(type,contesto=0)
    if ((self.type=='weighted' &&type=='update') || type=='weighted') then
        self.weighted(type, contesto)
    else
      self.regressione(type,contesto)
    end
  end

  def regressione(type,contesto=0) #contesto è utile solo se type= update

    case contesto
    when 0
      udata= self.data_store.data
      pdata= self.data_store_1.data
      rating= self.utenti[self.centroide-1].context_1
    when 1
      udata= self.data_store_1.data
      uy= rating= self.utenti[self.centroide-1].context_1
      pdata= self.data_store_2.data
      rating= self.utenti[self.centroide-1].context_2
    when 2
      udata= self.data_store_2.data
      uy= rating= self.utenti[self.centroide-1].context_2
      pdata= self.data_store_3.data
     rating= self.utenti[self.centroide-1].context_3
    end

    case type
    when 'update'
      self.method.update(udata,uy)
    when 'ridge'
      self.type=type
       if self.method==nil
       self.method= RidgeRegression.new(self.data_store.data, self.utenti[self.centroide].no_context)
        end
       when 'linear'
         self.type=type
         if self.method==nil
        self.method= LinearRegression.new(self.data_store.data, self.utenti[self.centroide].no_context)
         end
    when 'quadratic'
      self.type=type
         if self.method==nil
        self.method= QuadraticRegression.new(self.data_store.data, self.utenti[self.centroide].no_context)
         end
    when 'exponential'
      self.type=type
         if self.method==nil
        self.method= ExponentialRegression.new(self.data_store.data, self.utenti[self.centroide].no_context)
         end
    end

    regressione= self.method.regressione(pdata)

    return self.build_solution(regressione, rating)

  end

  def weighted(type,contesto=0)
    case contesto
      when 0
      udata= self.data_store.data
      uy=self.utenti[self.centroide-1].no_context
      pdata= self.data_store_1.data
      rating= self.utenti[self.centroide-1].context_1
    when 1
      udata= self.data_store_1.data
      uy= rating= self.utenti[self.centroide-1].context_1
      pdata= self.data_store_2.data
      rating= self.utenti[self.centroide-1].context_2
    when 2
      udata= self.data_store_2.data
      uy= rating= self.utenti[self.centroide-1].context_2
      pdata= self.data_store_3.data
     rating= self.utenti[self.centroide-1].context_3
    end

    case type
    when 'cosine'
      self.type=type
      s= CosineSim.new()
      sim=s.vector_matrix(udata, uy)
    when 'pearson'
      self.type=type
            p= Pearson.new()
      sim=p.ind_per_matrix(udata, uy)
    when 'jaccard'
      self.type=type
            j= Jaccard.new()
      sim=j.ind_jac_matrix(udata, uy)
    end

        case self.type
    when 'cosine'
      s= CosineSim.new()
      sim=s.vector_matrix(udata, uy)
    when 'pearson'
            j= Pearson.new()
      sim=j.ind_per_matrix(udata, uy)
    when 'jaccard'
            j= Jaccard.new()
      sim=j.ind_jac_matrix(udata, uy)
    end

             if self.method==nil
        self.method= WeightedSum.new(sim)
             else
               self.method.update(sim)
         end

    predizione= self.method.weighted_sum(pdata)

    return self.build_solution(predizione, rating)
  end
   def scored(type,contesto=0)
    case contesto
      when 0
      udata= self.data_store.data
      uy=self.utenti[self.centroide-1].no_context
      pdata= self.data_store_1.data
      rating= self.utenti[self.centroide-1].context_1
    when 1
      udata= self.data_store_1.data
      uy= rating= self.utenti[self.centroide-1].context_1
      pdata= self.data_store_2.data
      rating= self.utenti[self.centroide-1].context_2
    when 2
      udata= self.data_store_2.data
      uy= rating= self.utenti[self.centroide-1].context_2
      pdata= self.data_store_3.data
     rating= self.utenti[self.centroide-1].context_3
    end

    case type
    when 'cosine'
      self.type=type
      s= CosineSim.new()
      sim=s.vector_matrix(udata, uy)
    when 'pearson'
      self.type=type
            p= Pearson.new()
      sim=p.ind_per_matrix(udata, uy)
    when 'jaccard'
      self.type=type
            j= Jaccard.new()
      sim=j.ind_jac_matrix(udata, uy)
    end

        case self.type
    when 'cosine'
      s= CosineSim.new()
      sim=s.vector_matrix(udata, uy)
    when 'pearson'
            j= Pearson.new()
      sim=j.ind_per_matrix(udata, uy)
    when 'jaccard'
            j= Jaccard.new()
      sim=j.ind_jac_matrix(udata, uy)
    end

             if self.method==nil
        self.method= WeightedSum.new(sim)
             else
               self.method.update(sim)
         end

    predizione= self.method.scored_weight(pdata)

    return self.build_solution(predizione, rating)
  end
  # Costruisce il vettore della soluzione
  def build_solution(predizione,rating)
       b= Bench.new()

       ndcg= b.benchmark_coppia_ndcg(rating, predizione)
       chi= b.benchmark_coppia_chisquare(rating, predizione)
       mae= b.benchmark_coppia_mae(rating, predizione)
       rmse= b.benchmark_coppia_rmse(rating, predizione)
       nrmse= b.benchmark_coppia_nrmse(rating, predizione)
       rsquare= b.benchmark_coppia_Rsquare(rating, predizione)
       hitrate= b.benchmark_coppia_hitrate(rating, predizione)


  data_vector= {'utente'=>self.centroide,'predizione'=>predizione,'rating'=>rating,
                      'mae'=>mae,'rmse'=> rmse, 'nrmse'=>nrmse, 'chi'=>chi, 'rsquare'=>rsquare, 'hitrate'=>hitrate,
                      'ndcg'=>ndcg}

    return data_vector

  end
  def centroide
  @centroide
  end
  def utenti
    @utenti
  end
  def data
    @data
  end
  def data_1
    @data_1
  end
    def data_2
    @data_2
    end
    def data_3
    @data_3
    end
    def type
      @type
    end
    def method
      @method
    end
end
